﻿namespace TestTool.GUI.Utils
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text.RegularExpressions;

    internal class FilterValidation
    {
        private static void ExtractExpressions(List<ExpressionInfo> expressions, FilterValidationInfo validationInfo)
        {
            int idx = 0;
            while (idx < expressions.Count)
            {
                if (!ParseNextExpression(idx, expressions, validationInfo))
                {
                    idx++;
                }
            }
        }

        private static bool IsValidBoolExpression(string expression, out string error)
        {
            Regex regex = new Regex(@"^boolean(\s)*\(/");
            if (!regex.IsMatch(expression))
            {
                error = "expression should start with \"boolean(/\"";
                return false;
            }
            Regex regex2 = new Regex(@"^boolean(\s)*\(/(/([A-Za-z0-9])+)+(\s)*\[");
            if (!regex2.IsMatch(expression))
            {
                error = "element path should be in form /ElementName[/ElementName]... ";
                return false;
            }
            Regex regex3 = new Regex(@"^boolean(\s)*\(/(/([A-Za-z0-9])+)+(\s)*\[@?([A-Za-z0-9])+(\s)*");
            if (!regex3.IsMatch(expression))
            {
                error = "Node name can contain only alphanumeric symbols and '@' ('@' only at the beginning)";
                return false;
            }
            Regex regex4 = new Regex(@"^boolean(\s)*\(/(/([A-Za-z0-9])+)+(\s)*\[@?([A-Za-z0-9])+(\s)*(=|>|<|!=|<=|>=)");
            if (!regex4.IsMatch(expression))
            {
                error = "operator can be one of the following: =, !=, >, >=, <, <=";
                return false;
            }
            bool flag5 = new Regex("^boolean(\\s)*\\(/(/([A-Za-z0-9])+)+(\\s)*\\[@?([A-Za-z0-9])+(\\s)*(=|>|<|!=|<=|>=)(\\s)*\"([A-Za-z0-9\\.\\-])+\"\\]\\)$").IsMatch(expression);
            if (!flag5)
            {
                error = "right operand should be quoted string";
                return flag5;
            }
            error = null;
            return flag5;
        }

        private static bool IsValidExpression(string expression, out string error)
        {
            error = string.Empty;
            if (expression.StartsWith("b", StringComparison.CurrentCultureIgnoreCase))
            {
                return IsValidBoolExpression(expression.ToLower(), out error);
            }
            if (expression.StartsWith("c", StringComparison.CurrentCultureIgnoreCase))
            {
                return IsValidSearchExpression(expression.ToLower(), out error);
            }
            error = "expression should start with \"boolean\" or \"contains\"";
            return false;
        }

        private static bool IsValidSearchExpression(string expression, out string error)
        {
            error = null;
            Regex regex = new Regex(@"^contains(\s)*\(/");
            if (!regex.IsMatch(expression))
            {
                error = "expression should start with \"contains(/\"";
                return false;
            }
            Regex regex2 = new Regex(@"^^contains(\s)*\((\s)*(/([A-Za-z0-9])+)+(\s)*");
            if (!regex2.IsMatch(expression))
            {
                error = "element path should be in form /ElementName[/ElementName]... ";
                return false;
            }
            bool flag3 = new Regex("^contains(\\s)*\\((\\s)*(/([A-Za-z0-9])+)+(\\s)*\\,(\\s)*\"([A-Za-z0-9])+\"(\\s)*\\)$").IsMatch(expression);
            if (!flag3)
            {
                error = "right operand should be quoted string";
            }
            return flag3;
        }

        private static bool ParseNextExpression(int idx, List<ExpressionInfo> expressions, FilterValidationInfo validationInfo)
        {
            int num5;
            ExpressionInfo info = expressions[idx];
            string expression = expressions[idx].Expression.Trim();
            List<Range> constants = new List<Range>();
            List<Range> braces = new List<Range>();
            bool flag = false;
            int num = -1;
            Range item = null;
            while ((num = expression.IndexOf('"', num + 1)) != -1)
            {
                flag = !flag;
                if (flag)
                {
                    item = new Range {
                        Left = num
                    };
                }
                else
                {
                    item.Right = num;
                    constants.Add(item);
                }
            }
            if (flag)
            {
                validationInfo.Valid = false;
                validationInfo.Message = "Constant not terminated";
                return false;
            }
            int num2 = 0;
            int startIndex = 0;
            int num4 = -1;
        Label_00A0:
            num5 = expression.IndexOf('(', startIndex);
            int index = expression.IndexOf(')', startIndex);
            if ((num5 != -1) || (index != -1))
            {
                if ((num5 < index) && (num5 != -1))
                {
                    if (num2 == 0)
                    {
                        num4 = num5;
                    }
                    startIndex = num5 + 1;
                    num2++;
                }
                else
                {
                    num2--;
                    if (num2 == 0)
                    {
                        Range range2 = new Range {
                            Left = num4,
                            Right = index
                        };
                        braces.Add(range2);
                    }
                    startIndex = index + 1;
                }
                goto Label_00A0;
            }
            if (num2 != 0)
            {
                validationInfo.Valid = false;
                validationInfo.Message = "Bracket expected";
                return false;
            }
            if ((from R in braces
                where (R.Left == 0) && (R.Right == (expression.Length - 1))
                select R).FirstOrDefault<Range>() != null)
            {
                expressions.RemoveAt(idx);
                string str = expression.Substring(1, expression.Length - 2).Trim();
                ExpressionInfo info2 = new ExpressionInfo {
                    Expression = str
                };
                int num7 = 1;
                while (expression[num7] == ' ')
                {
                    num7++;
                }
                info2.Left = info.Left + num7;
                int num8 = 1;
                while (expression[expression.Length - num8] == ' ')
                {
                    num8++;
                }
                info2.Right = info.Right - num8;
                expressions.Add(info2);
                return true;
            }
            return (Split("or", true, expressions, idx, constants, braces, validationInfo) || (Split("and", true, expressions, idx, constants, braces, validationInfo) || (Split("not", false, expressions, idx, constants, braces, validationInfo) || (!validationInfo.Valid && false))));
        }

        private static bool Split(string op, bool binary, List<ExpressionInfo> expressions, int idx, List<Range> constants, List<Range> braces, FilterValidationInfo validationInfo)
        {
            Func<Range, bool> func = null;
            Func<Range, bool> func2 = null;
            ExpressionInfo info = expressions[idx];
            string expression = info.Expression;
            for (int operatorPosition = expression.IndexOf(op, 0, StringComparison.InvariantCultureIgnoreCase); operatorPosition != -1; operatorPosition = expression.IndexOf(op, operatorPosition + 1, StringComparison.InvariantCultureIgnoreCase))
            {
                if (func == null)
                {
                    func = R => (R.Left < operatorPosition) && (R.Right > operatorPosition);
                }
                if (Enumerable.Where<Range>(constants, func).FirstOrDefault<Range>() == null)
                {
                    if (func2 == null)
                    {
                        func2 = R => (R.Left < operatorPosition) && (R.Right > operatorPosition);
                    }
                    if (Enumerable.Where<Range>(braces, func2).FirstOrDefault<Range>() == null)
                    {
                        if (!binary && (operatorPosition != 0))
                        {
                            validationInfo.Valid = false;
                            validationInfo.Message = "Operator not found";
                            return false;
                        }
                        if (binary && (operatorPosition == 0))
                        {
                            validationInfo.Valid = false;
                            validationInfo.Message = "Operand missing";
                            return false;
                        }
                        expressions.RemoveAt(idx);
                        if (binary)
                        {
                            string str2 = expression.Substring(0, operatorPosition - 1).Trim();
                            ExpressionInfo info2 = new ExpressionInfo {
                                Expression = str2
                            };
                            int num = 0;
                            while (expression[num] == ' ')
                            {
                                num++;
                            }
                            info2.Left = info.Left + num;
                            info2.Right = info2.Left + str2.Length;
                            expressions.Add(info2);
                        }
                        string str3 = expression.Substring(operatorPosition + op.Length).Trim();
                        ExpressionInfo item = new ExpressionInfo {
                            Expression = str3
                        };
                        int num2 = operatorPosition + op.Length;
                        while (expression[num2] == ' ')
                        {
                            num2++;
                        }
                        item.Left = info.Left + num2;
                        item.Right = item.Left + item.Expression.Length;
                        expressions.Add(item);
                        return true;
                    }
                }
            }
            return false;
        }

        public static FilterValidationInfo Validatefilter(string expression)
        {
            FilterValidationInfo validationInfo = new FilterValidationInfo {
                Valid = true
            };
            if (!string.IsNullOrEmpty(expression))
            {
                List<ExpressionInfo> expressions = new List<ExpressionInfo>();
                ExpressionInfo item = new ExpressionInfo();
                int num = 0;
                while (expression[num] == ' ')
                {
                    num++;
                }
                int num2 = expression.Length - 1;
                while (expression[num2] == ' ')
                {
                    num2--;
                }
                item.Expression = expression;
                item.Left = num;
                item.Right = num2;
                expressions.Add(item);
                ExtractExpressions(expressions, validationInfo);
                if (!validationInfo.Valid)
                {
                    return validationInfo;
                }
                foreach (ExpressionInfo info3 in expressions)
                {
                    string str;
                    bool flag = IsValidExpression(info3.Expression, out str);
                    validationInfo.Valid &= flag;
                    if (!flag)
                    {
                        info3.Error = str;
                        validationInfo.IncorrectExpressions.Add(info3);
                    }
                }
            }
            return validationInfo;
        }

        private class Range
        {
            public int Left { get; set; }

            public int Right { get; set; }
        }
    }
}

